package com.amado.course50java8;

import java.beans.Introspector;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;

/**
 * 添加参数vm options:  -Djdk.internal.lambda.dumpProxyClasses=D:\temp
 * 查看Lambda生成的类，再反编译查查看
 *
 * private final Object writeReplace() {
 *    return new SerializedLambda(Java80Lambda.class, "com/amado/course50java8/Java80Lambda$Func", "func", "()Ljava/lang/String;", 5, "com/amado/course50java8/Java80Lambda$Student", "getName", "()Ljava/lang/String;", "()Ljava/lang/String;", new Object[]{this.arg$1});
 * }
 *
 */
public class Java80Lambda {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("1234");
        Func func = student::getName;
        System.out.println(func.func());
        System.out.println(getPropertyName(student::getName));
    }

    @FunctionalInterface
    interface Func<T> extends Serializable {
        String func();
    }

    public static <T> String getPropertyName(Func<T> lambda) {
        try {
            //writeReplace从哪里来的？后面会讲到
            Method method = lambda.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            //调用writeReplace()方法，返回一个SerializedLambda对象
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(lambda);
            //得到lambda表达式中调用的方法名，如 "User::getSex"，则得到的是"getSex"
            String getterMethod = serializedLambda.getImplMethodName();
            //去掉”get"前缀，最终得到字段名“sex"
            String fieldName = Introspector.decapitalize(getterMethod.replace("get", ""));
            return fieldName;
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    static class Student {
        private String name;
        private Integer age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }
    }
}